<?php

class Materials_Model_Category extends Workset_Model_Object_Abstract implements Workset_Model_Object_TreeNode_Interface
{

    const TYPE = 'materials_category';

    protected $_objectType = self::TYPE;

    /**
     * Возвращает объект Materials_Model_Category по primary key
     *
     * @static
     * @param  mixed $identity
     * @return Catalogue_Model_Object
     *
     */
	static function getInstance($identity) {
		$storage = self::getDefaultStorage(self::TYPE);
		return self::getFromStorage($storage, $identity);
	}

    /**
     * Создает новый объект Materials_Model_Category с полями $data
     *
     * @static
     * @param  array $data
     * @return Catalogue_Model_Object
     *
     */
	static function create($data) {
		$storage = self::getDefaultStorage(self::TYPE);
		return $storage->create(self::getInputData($data));
	}

    /**
     * Возвращает список категорий
     *
     * @static
     * @param  mixed $where
     * @param  mixed $order
     * @param  int $limit
     * @param  int $offset
     * @return Workset_Model_Object_Iterator
     *
     */
    static function getAll($where = null, $order = null, $limit = null, $offset = null, $offsetByPage = false) {
        $storage = self::getDefaultStorage(self::TYPE);
        return $storage->getAll($where, $order, $limit, $offset, $offsetByPage);
    }

    /**
     * Возвращает материалы по пренадлежности их к категории
     *
     * @static
     * @param  array|Workset_Model_Object_Iterator $diff
     * @param  array|Workset_Model_Object_Iterator $intersect
     * @param  $where
     * @param  $order
     * @param  int $limit
     * @param  int $offset
     * @param  bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
	static function getCategoryMaterials($diff = null, $intersect = null, $where = null,
                                         $order = null, $limit = null, $offset = null, $offsetByPage = false)
    {
		$storage = self::getDefaultStorage(self::TYPE);
		return $storage->getCategoryMaterials($diff, $intersect, $where, $order, $limit, $offset, $offsetByPage);
	}
	
    /**
     * Возвращает материалы по пренадлежности их к категории материалов ( и категории каталога )
     *
     * @static
     * @param  array|Workset_Model_Object_Iterator $diffCatalogue
     * @param  array|Workset_Model_Object_Iterator $intersectCatalogue
     * @param  array|Workset_Model_Object_Iterator $diff
     * @param  array|Workset_Model_Object_Iterator $intersect
     * @param  $where
     * @param  $order
     * @param  int $limit
     * @param  int $offset
     * @param  bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
	static function getCatalogueCategoryMaterials($diffCatalogue = null, $intersectCatalogue = null, $diff = null, $intersect = null, $where = null,
                                         		  $order = null, $limit = null, $offset = null, $offsetByPage = false)
    {
		$storage = self::getDefaultStorage(self::TYPE);
		return $storage->getCatalogueCategoryMaterials($diffCatalogue, $intersectCatalogue, $diff, $intersect, $where, $order, $limit, $offset, $offsetByPage);
	}

    /**
     * Возвращает материалы по пренадлежности их к категории с проверкой статуса публикации
     * для использования в публичной части сайта
     *
     * @static
     * @param  bool $checkPublished - проверять статус публикации
     * @param  array|Workset_Model_Object_Iterator $diff
     * @param  array|Workset_Model_Object_Iterator $intersect
     * @param  $where
     * @param  $order
     * @param  int $limit
     * @param  int $offset
     * @param  bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
    static function getPublishedCategoryMaterials($checkPublished = true, $diff = null, $intersect = null, $where = null,
                                 $order = null, $limit = null, $offset = null, $offsetByPage = false) {

        if (true == $checkPublished) {
            $where = (array)$where;

            array_unshift($where, 'pub_date_start is null OR pub_date_start <= UNIX_TIMESTAMP()');
            array_unshift($where, 'status = '.Materials_Model_Material::STATUS_PUBLISHED);
        }

        return self::getCategoryMaterials(
            $diff, $intersect, $where,
            $order, $limit, $offset, $offsetByPage
        );

    }
    
    /**
     * Возвращает материалы по пренадлежности их к категории материалов ( и категории каталога ) с проверкой статуса публикации
     * для использования в публичной части сайта
     *
     * @static
     * @param  bool $checkPublished - проверять статус публикации
     * @param  array|Workset_Model_Object_Iterator $diffCatalogue
     * @param  array|Workset_Model_Object_Iterator $intersectCatalogue
     * @param  array|Workset_Model_Object_Iterator $diff
     * @param  array|Workset_Model_Object_Iterator $intersect
     * @param  $where
     * @param  $order
     * @param  int $limit
     * @param  int $offset
     * @param  bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
    static function getPublishedCatalogueCategoryMaterials($checkPublished = true, $diffCatalogue = null, $intersectCatalogue = null, $diff = null, $intersect = null, $where = null,
                                 $order = null, $limit = null, $offset = null, $offsetByPage = false) {

        if (true == $checkPublished) {
            $where = (array)$where;

            array_unshift($where, 'pub_date_start is null OR pub_date_start <= UNIX_TIMESTAMP()');
            array_unshift($where, 'status = '.Materials_Model_Material::STATUS_PUBLISHED);
        }

        return self::getCatalogueCategoryMaterials(
            $diffCatalogue, $intersectCatalogue, $diff, $intersect, $where,
            $order, $limit, $offset, $offsetByPage
        );

    }
    
    /**
     * Возвращает список категорий по коду
     *
     * @static
     * @param  string $code
     * @param  mixed $where
     * @param  mixed $order
     * @param  int $limit
     * @param  int $offset
     * @return Workset_Model_Object_Iterator
     *
     */
    static function getByCode($code, $where = null, $order = null,
                              $limit = null, $offset = null, $offsetByPage = false )
    {
    	$where['code = ?'] = $code;
    	return self::getAll( $where, $order, $limit, $offset, $offsetByPage );
    }

    /**
     * Инициализация объекта
     *
     * @return void
     */
	public function init() {
		$this->attach(new Workset_Model_Observer_TreeNodeUpdater('categories'));
	}

    /**
     * @param  $data
     * @return Materials_Model_Category
     */
    public function setData($data) {
        return parent::setData(self::getInputData($data));
    }

    /**
     * Увеличивает счетчик материалов (вызывается при сохранении нового объекта)
     *
     * @return Materials_Model_Category
     */
    public function incrementMaterials() {
        $this['materials'] += 1;
        $this->_update = true;

        return $this;
    }

    /**
     * Уменьшает счетчик материалов (вызывается при удалении объекта)
     * 
     * @return Materials_Model_Category
     */
    public function decrementMaterials() {
        if ($this['materials'] > 0) {
            $this['materials'] -= 1;
            $this->_update = true;
        }
        return $this;
    }

    /**
     * Возвращает список материалов
     *
     * @param  $filter
     * @param  $order
     * @param  $limit
     * @param  $offset
     * @param bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
	public function getMaterials($filter = null, $order = null, $limit = null, $offset = null, $offsetByPage = false) {
		return $this->getStorage()->getMaterials($this, $filter, $order, $limit, $offset, $offsetByPage);
	}

    /**
     * Возвращает список опубликованных материалов 
     *
     * @param  $checkPublished
     * @param  $filter
     * @param  $order
     * @param  $limit
     * @param  $offset
     * @param bool $offsetByPage
     * @return Workset_Model_Object_Iterator
     */
    public function getPublishedMaterials($checkPublished, $filter = null, $order = null, $limit = null,
                                          $offset = null, $offsetByPage = false)
    {
        $intersect = array($this->getId());

        return self::getPublishedCategoryMaterials( $checkPublished, null, $intersect, $filter,
                                                    $order, $limit, $offset, $offsetByPage );
    }

    /**
     * Возвращает количество материалов у категории
     *
     * @return int
     */
    public function getMaterialsCount() {
        return (int)$this['materials'];
    }

    /**
     * Возвращает количество материалов у категории с возможностью фильтрации
     *
     * @param  $filter
     * @return int
     */
    public function materialsCount($filter = null) {
        return $this->getStorage()->materialsCount($this, $filter);
    }

    /**
     * Возвращает ID родительской категории
     *
     * @return int
     */
    public function getParentId() {
        if ($this->_data['parent_id'] > 0) {
            return $this->_data['parent_id'];
        } else {
            return null;
        }
    }

    /**
     * Устанавливает ID ролителя для категории
     * 
     * @param  $parentId
     * @return Materials_Model_Category
     */
    public function setParentId($parentId) {
        if ($parentId > 0) {
            $this['parent_id'] = (int)$parentId;
        }
        return $this;
    }

	/**
	 * Устанавливает родительскую категорию
	 *
	 * @param Workset_Model_Object_TreeNode_Interface $parent
	 * @return Materials_Model_Category
	 */
	public function setParent(Workset_Model_Object_TreeNode_Interface $parent) {
		if ($parent instanceof Materials_Model_Category) {
			$this->setParentId($parent->getId());
		}
		return $this;
	}

    /**
	 * Возвращает родительскую категорию
	 *
     * @return Materials_Model_Category
     *
     */
    public function getParent() {
        $parentId = $this->getParentId();
        if ($parentId > 0) {
            return Materials_Model_Category::getInstance($parentId);
        }
        return null;
    }

    /**
     * Проверяет, есть ли родительская категория
     *
     * @return bool
     */
    public function hasParent() {
        return $this->getParentId() > 0;
    }

    /**
     * @return bool
     *
     * Есть ли дочерние категории
     */
    public function hasChilds() {
        return $this->_data['categories'] > 0;
    }

    /**
     * Возвращает уровень вложенности категории
     *
     * @return void
     */
    public function getDepth() {
        return (int)$this->_data['depth'];
    }

    /**
	 * @deprecated
     * @return Catalogue_Model_Category
     *
     * Увеличивает счетчик вложенных категорий
     */
    public function incrementCategoriesCount() {
        $this['categories'] += 1;
        return $this;
    }

    /**
	 * @deprecated
     * @return Catalogue_Model_Category
     *
     * Уменьшает счетчик вложенных категорий
     */
    public function decrementCategoriesCount() {
        if ($this['categories'] > 0) {
            $this['categories'] -= 1;
        }
        return $this;
    }

    /**
     * @return string
     *
     * Сохраняет категорию (добавляет в хранилище новую категорию или обновляет существующую)
     */
    public function save() {
		$this['depth'] = $this->_calcDepth();
        return parent::save();
    }

    /**
     * @return int
     *
     * Вычисляет уровень вложенности категории
     */
    protected function _calcDepth() {
        if (!$this->hasParent()) {
            return 0;
        } else {
            return $this->getParent()->getDepth() + 1;
        }
    }

    /**
     * Преобразует поля объекта во внутренний формат (для хранения в БД)
     *
     * @static
     * @param
     * @return array
     *
     */
    static function getInputData($data, $key = null) {
        if (null !== $key) {
            $inputData = array($key => $data[$key]);
        } elseif ($data instanceof Workset_Model_Object_Interface) {
            $inputData = $data->toArray();
        } else {
            $inputData = $data;
        }

        foreach ($inputData as $key => $value) {
            switch ($key) {
                case 'pub_date':

                    if (!empty($data['pub_time'])) {
                        $time = self::inputTimeFormat($data['pub_time']);
                        $checkTime = false;
                    } else {
                        $time = 0;
                        $checkTime = true;
                    }

                    $inputData[$key] = self::inputDateFormat($value, null, $checkTime);

                    if ($time > 0) {
                        $inputData[$key] += $time;
                    }

                break;
            }
        }

        return $inputData;
    }

    /**
     * Преобразует поля для отображения на сайте
     *
     * @static
     * @param  $data
     * @param  $key
     * @return array
     *
     */
    static function getOutputData($data, $key = null) {
        if (null !== $key) {
            $outputData = array($key => $data[$key]);
        } elseif ($data instanceof Workset_Model_Object_Interface) {
            $outputData = $data->toArray();
        } else {
            $outputData = $data;
        }

        foreach ($outputData as $key => $value) {
            switch ($key) {
                case 'pub_date':
                    $outputData[$key] = self::outputDateFormat($value, null, self::$_dateFormat);
                break;
            }
        }

        return $outputData;
    }

}

?>